#include "zos_config.h"

#ifdef BOARD_USING_I2C_OLED

#include "zos.h"
#include "oled.h"
#include "oled_zk.h"

//C库
#include <stdarg.h>
#include <stdio.h>

#define OLED_ADDRESS		0x3C
#define OLED_WRITE_CMD 		0x00
#define OLED_WRITE_DATE 	0x40

/************************************************************
*	函数名称：	oled_write_data
*
*	函数功能：	OLED写入一个数据
*
*	入口参数：	byte：需要写入的数据
*
*	返回参数：	写入结果
*
*	说明：		0-成功		1-失败
************************************************************/
static _Bool oled_write_data(unsigned char byte)
{
	zos_uint8_t buf[2];
	
	buf[0]=OLED_WRITE_DATE;
	buf[1]=byte;

	if(zos_i2c_write(ZOS_I2C_BUS_0,OLED_ADDRESS,buf,2) == ZOS_EOK)
	{
		return ZOS_EOK;
	}
	else
	{
		zos_printf("oled write data error,plese check i2c gpio init\r\n");
		return ZOS_ERROR;
	}
}

/*
************************************************************
*	函数名称：	oled_write_cmd
*
*	函数功能：	OLED写入一个命令
*
*	入口参数：	cmd：需要写入的命令
*
*	返回参数：	写入结果
*
*	说明：		0-成功		1-失败
************************************************************
*/
static _Bool oled_write_cmd(unsigned char cmd)
{
	zos_uint8_t buf[2];
	
	buf[0]=OLED_WRITE_CMD;
	buf[1]=cmd;
	
	if(zos_i2c_write(ZOS_I2C_BUS_0,OLED_ADDRESS,buf,2) == ZOS_EOK)
	{
		return ZOS_EOK;
	}
	else
	{
		zos_printf("oled write cmd error,plese check i2c gpio init\r\n");
		return ZOS_ERROR;
	}
}

/*
************************************************************
*	函数名称：	oled_init
*
*	函数功能：	OLED初始化
*
*	入口参数：	无
*
*	返回参数：	无
*
*	说明：		
************************************************************
*/
void oled_init(void)
{
	ZOS_I2C_CONFIG i2c_cfg;

	i2c_cfg.mode = ZOS_I2C_MODE_MASTER;
	i2c_cfg.speed = ZOS_I2C_SPEED_400K;
	zos_i2c_init(ZOS_I2C_BUS_0,&i2c_cfg);
	zos_task_delay(100);
#if 0
	oled_write_cmd(0xAE); //关闭显示
	oled_write_cmd(0x20); //Set Memory Addressing Mode	
	oled_write_cmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	oled_write_cmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
	oled_write_cmd(0xa0); //0xa0，X轴正常显示；0xa1，X轴镜像显示
	oled_write_cmd(0xc0); //0xc0，Y轴正常显示；0xc8，Y轴镜像显示
	oled_write_cmd(0x00); //设置列地址低4位
	oled_write_cmd(0x10); //设置列地址高4位
	oled_write_cmd(0x40); //设置起始线地址
	oled_write_cmd(0x81); //设置对比度值
	oled_write_cmd(0x7f); //------
	oled_write_cmd(0xa6); //0xa6,正常显示模式;0xa7，
	oled_write_cmd(0xa8); //--set multiplex ratio(1 to 64)
	oled_write_cmd(0x3F); //------
	oled_write_cmd(0xa4); //0xa4,显示跟随RAM的改变而改变;0xa5,显示内容忽略RAM的内容
	oled_write_cmd(0xd3); //设置显示偏移
	oled_write_cmd(0x00); //------
	oled_write_cmd(0xd5); //设置内部显示时钟频率
	oled_write_cmd(0xf0); //------
	oled_write_cmd(0xd9); //--set pre-charge period//
	oled_write_cmd(0x22); //------
	oled_write_cmd(0xda); //--set com pins hardware configuration//
	oled_write_cmd(0x12); //------
	oled_write_cmd(0xdb); //--set vcomh//
	oled_write_cmd(0x20); //------
	oled_write_cmd(0x8d); //--set DC-DC enable//
	oled_write_cmd(0x14); //------
	oled_write_cmd(0xaf); //打开显示
#else
	oled_write_cmd(0xAE);//--turn off oled panel
	oled_write_cmd(0x00);//---set low column address
	oled_write_cmd(0x10);//---set high column address
	oled_write_cmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	oled_write_cmd(0x81);//--set contrast control register
	oled_write_cmd(0xCF); // Set SEG Output Current Brightness
	oled_write_cmd(0xA1);//--Set SEG/Column Mapping     0xa0???? 0xa1??
	oled_write_cmd(0xC8);//Set COM/Row Scan Direction   0xc0???? 0xc8??
	oled_write_cmd(0xA6);//--set normal display
	oled_write_cmd(0xA8);//--set multiplex ratio(1 to 64)
	oled_write_cmd(0x3f);//--1/64 duty
	oled_write_cmd(0xD3);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	oled_write_cmd(0x00);//-not offset
	oled_write_cmd(0xd5);//--set display clock divide ratio/oscillator frequency
	oled_write_cmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
	oled_write_cmd(0xD9);//--set pre-charge period
	oled_write_cmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	oled_write_cmd(0xDA);//--set com pins hardware configuration
	oled_write_cmd(0x12);
	oled_write_cmd(0xDB);//--set vcomh
	oled_write_cmd(0x40);//Set VCOM Deselect Level
	oled_write_cmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
	oled_write_cmd(0x02);//
	oled_write_cmd(0x8D);//--set Charge Pump enable/disable
	oled_write_cmd(0x14);//--set(0x10) disable
	oled_write_cmd(0xA4);// Disable Entire Display On (0xa4/0xa5)
	oled_write_cmd(0xA6);// Disable Inverse Display On (0xa6/a7) 
	oled_write_cmd(0xAF);//--turn on oled panel
	
	oled_write_cmd(0xAF); /*display ON*/ 
	oled_clear_screen();
#endif

}

/*
************************************************************
*	函数名称：	oled_set_address
*
*	函数功能：	设置OLED显示地址
*
*	入口参数：	x：行地址
*				y：列地址
*
*	返回参数：	无
*
*	说明：		
************************************************************
*/
void oled_set_address(unsigned char x, unsigned char y)
{

	oled_write_cmd(0xb0 + x);					//设置行地址
	//zos_task_delay_us(5);
	oled_write_cmd(((y & 0xf0) >> 4) | 0x10);	//设置列地址的高4位
	//zos_task_delay_us(5);
	oled_write_cmd(y & 0x0f);					//设置列地址的低4位
	//zos_task_delay_us(5);
	
}

/*
************************************************************
*	函数名称：	oled_clear_screen
*
*	函数功能：	OLED全屏清除
*
*	入口参数：	无
*
*	返回参数：	无
*
*	说明：		
************************************************************
*/
void oled_clear_screen(void)
{
	
	unsigned char i = 0, j = 0;
	
	zos_enter_critical();
	for(; i < 8; i++)
	{
		oled_write_cmd(0xb0 + i);
		oled_write_cmd(0x10);
		oled_write_cmd(0x00);
			
		for(j = 0; j < 128; j++)
		{
			oled_write_data(0x00);
		}
	}
	zos_exit_critical();
	
}

/*
************************************************************
*	函数名称：	oled_clear_line
*
*	函数功能：	OLED清除指定行
*
*	入口参数：	x：需要清除的行
*
*	返回参数：	无
*
*	说明：		
************************************************************
*/
void oled_clear_line(unsigned char x)
{

	unsigned char i = 0;
		
	oled_write_cmd(0xb0 + x);
	oled_write_cmd(0x10);
	oled_write_cmd(0x00);
			
	for(; i < 128; i++)
	{
		oled_write_data(0x00);
	}

}

/*
************************************************************
*	函数名称：	oled_dis_128x64_picture
*
*	函数功能：	显示一幅128*64的图片
*
*	入口参数：	dp：图片数据指针
*
*	返回参数：	无
*
*	说明：		
************************************************************
*/
void oled_dis_128x64_picture(const unsigned char *dp)
{
	
	unsigned char i = 0, j = 0;
	
		
	for(; j < 8; j++)
	{
		oled_set_address(j, 0);
		
		for (i = 0; i < 128; i++)
		{	
			oled_write_data(*dp++); //写数据到LCD,每写完一个8位的数据后列地址自动加1
		}
	}
	
}

/*
************************************************************
*	函数名称：	oled_dis_16x16_char
*
*	函数功能：	显示16x16的点阵数据
*
*	入口参数：	dp：图片数据指针
*
*	返回参数：	无
*
*	说明：		显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标
************************************************************
*/
void oled_dis_16x16_char(unsigned short x, unsigned short y, const unsigned char *dp)
{
	
	unsigned short i = 0, j = 0;
		
	for(j = 2; j > 0; j--)
	{
		oled_set_address(x, y);
		
		for (i = 0; i < 16; i++)
		{
			oled_write_data(*dp++);		//写数据到OLED,每写完一个8位的数据后列地址自动加1
		}
		
		x++;
	}
	
}

/*
************************************************************
*	函数名称：	oled_dis_6x8_string
*
*	函数功能：	显示6x8的点阵数据
*
*	入口参数：	x：显示行
*				y：显示列
*				fmt：不定长参
*
*	返回参数：	无
*
*	说明：		能显示7行
************************************************************
*/
void oled_dis_6x8_string(unsigned char x, unsigned char y, char *fmt, ...)
{

	unsigned char i = 0, ch = 0;
	unsigned char OledPrintfBuf[300];
	
	va_list ap;
	unsigned char *pStr = OledPrintfBuf;
	
	va_start(ap,fmt);
	vsprintf((char *)OledPrintfBuf, fmt, ap);
	va_end(ap);
	
	y += 2;
		
	while(*pStr != '\0')
	{
		ch = *pStr - 32;
		
		if(y > 126)
		{
			y = 2;
			x++;
		}
		
		oled_set_address(x, y);
		for(i = 0; i < 6; i++)
			oled_write_data(F6x8[ch][i]);
		
		y += 6;
		pStr++;
	}

}

/*
************************************************************
*	函数名称：	oled_dis_8x16_string
*
*	函数功能：	显示8x16的点阵数据
*
*	入口参数：	x：显示行
*				y：显示列
*				fmt：不定长参
*
*	返回参数：	无
*
*	说明：		能显示4行
************************************************************
*/
void oled_dis_8x16_string(unsigned char x, unsigned char y, char *fmt, ...)
{

	unsigned char i = 0, ch = 0;
	unsigned char OledPrintfBuf[300];
	
	va_list ap;
	unsigned char *pStr = OledPrintfBuf;
	
	va_start(ap,fmt);
	vsprintf((char *)OledPrintfBuf, fmt, ap);
	va_end(ap);
	
	y += 2;
		
	while(*pStr != '\0')
	{
		ch = *pStr - 32;
			
		if(y > 128)
		{
			y = 2;
			x += 2;
		}
			
		oled_set_address(x, y);
		for(i = 0; i < 8; i++)
			oled_write_data(F8X16[(ch << 4) + i]);
		
		oled_set_address(x + 1, y);
		for(i = 0; i < 8; i++)
			oled_write_data(F8X16[(ch << 4) + i + 8]);
		
		y += 8;
		pStr++;
	}

}

zos_err_t string_get_cn_bit_map(zos_uint8_t *font)
{
	zos_uint32_t i,count=strlen(cn_check);
	for(i=0;i<count;i+=3)
	{
		if(((zos_uint8_t)cn_check[i])==*font)
		{
			if (cn_check[i+1] == *(font+1) && cn_check[i+2] == *(font+2))
			{
				break;
			}
			
		}
	}
	if(i >= count)
	{
		return ZOS_ERROR;
	}
	return i/3;
	
}


/*
************************************************************
*	函数名称：	oled_dis_16x16_string
*
*	函数功能：	显示16x16的点阵数据
*
*	入口参数：	x：显示行
*				y：显示列
*				fmt：不定长参
*
*	返回参数：	无
*
*	说明：		能显示4行
************************************************************
*/
void oled_dis_16x16_string(unsigned char x, unsigned char y, char *fmt, ...)
{

	unsigned char i,ch = 0;
	unsigned char OledPrintfBuf[300];
	unsigned int str_len,status=1;
	char font_index=0;
	str_len=strlen(cn_check);
	va_list ap;
	unsigned char *pStr = OledPrintfBuf;
	
	va_start(ap,fmt);
	vsprintf((char *)OledPrintfBuf, fmt, ap);
	va_end(ap);
	
	y += 2;
	while(*pStr != '\0')
	{
		if((*pStr&0xff)>0x80)
		{
			font_index = string_get_cn_bit_map(pStr);
			if(font_index == ZOS_ERROR)
			{
				zos_printf("no find this font\r\n");
				pStr++;
			}
			else
			{
				oled_dis_16x16_char(x,y,cn[font_index]);
				pStr+=3;
				
			}
			y+=16;
		}
		else
		{
			ch = *pStr - 32;
			
			if(y > 128)
			{
				y = 2;
				x += 2;
			}
				
			oled_set_address(x, y);
			for(i = 0; i < 8; i++)
				oled_write_data(F8X16[(ch << 4) + i]);
			
			oled_set_address(x + 1, y);
			for(i = 0; i < 8; i++)
				oled_write_data(F8X16[(ch << 4) + i + 8]);
			
			y += 8;
			pStr++;
		}
	}
}


#endif
